/*
 * @lc app=leetcode id=449 lang=cpp
 *
 * [449] Serialize and Deserialize BST
 */

// @lc code=start
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        queue<TreeNode*> que;
        que.push(root);
        std::string res;
        while(!que.empty()) {
            auto p = que.front();
            que.pop();
            
            if (p == nullptr) {
                res += '$';
            } else {
                res += std::to_string(p->val) + " ";
                que.push(p->left);
                que.push(p->right);
            }
        }
        return res;
        
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if (data[0] == '$') {
            return nullptr;
        }

        int i = 0;
        auto next_token = [&]() -> std::string{
            std::string token;
            if (data[i] == ' '){
              i++;
            }
            if (data[i] == '$'){
                i++;
                token = "$";
            } else {
                while(data[i] != ' ') {
                    token += data[i];
                    i++;
                }
            }
            return token;
        };
        auto token = next_token();
        TreeNode  *root = new TreeNode(std::stoi(token));
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty()) {
            auto p = que.front();
            que.pop();
            if (p == nullptr) {
                continue;
            }
            auto token = next_token();
            if (token == "$") {
               p->left = nullptr;
            } else {
               p->left = new TreeNode(std::stoi(token));
            }
            que.push(p->left);
            token = next_token();
            if (token == "$") {
                p->right = nullptr;
            } else {
                p->right = new TreeNode(std::stoi(token));
            }
            que.push(p->right);
        }
        return root;        
    }
};

// Your Codec object will be instantiated and called as such:
// Codec* ser = new Codec();
// Codec* deser = new Codec();
// string tree = ser->serialize(root);
// TreeNode* ans = deser->deserialize(tree);
// return ans;
// @lc code=end

